#include <vector>
#include <iostream>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#define protected public
#define private public
#include "acl/ops/acl_dvpp.h"
#include "single_op/op_executor.h"
#include "single_op/dvpp/common/dvpp_util.h"
#include "single_op/dvpp/mgr/dvpp_manager.h"
#include "single_op/dvpp/base/image_processor.h"
#include "single_op/dvpp/v200/image_processor_v200.h"
#include "single_op/dvpp/v300/image_processor_v300.h"
#include "single_op/dvpp/v100/image_processor_v100.h"
#include "single_op/dvpp/common/dvpp_def_internal.h"
#undef private
#undef protected

#include "acl/acl.h"
#include "runtime/rt.h"
#include "aicpu/dvpp/dvpp_def.h"
#include "acl/ops/acl_dvpp.h"
#include "acl_stub.h"

using namespace std;
using namespace testing;
using namespace acl;
using namespace acl::dvpp;

namespace {
    acldvppChannelDesc desc;
    aclrtStream stream = nullptr;
    char globalMem[100];
}

class HimpiTest : public testing::Test {
protected:

    void SetUp() { }

    void TearDown()
    {
        Mock::VerifyAndClear((void *)(&MockFunctionTest::aclStubInstance()));
    }
};

TEST_F(HimpiTest, acldvppSetResizeConfigInterpolation)
{
    acl::dvpp::DvppManager &dvppManager = acl::dvpp::DvppManager::GetInstance();
    dvppManager.version_ = DVPP_KERNELS_V300;
    dvppManager.aclRunMode_ = ACL_HOST;
    dvppManager.InitDvppProcessor();
    acldvppResizeConfig conf;
    auto ret = acldvppSetResizeConfigInterpolation(&conf, 2);
    EXPECT_EQ(ret, ACL_SUCCESS);
    EXPECT_EQ(conf.dvppResizeConfig.interpolation, 2);
    ret = acldvppSetResizeConfigInterpolation(&conf, 6);
    EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(HimpiTest, acldvppCreateChannel)
{
    acl::dvpp::DvppManager &dvppManager = acl::dvpp::DvppManager::GetInstance();
    dvppManager.version_ = DVPP_KERNELS_V300;
    dvppManager.aclRunMode_ = ACL_HOST;
    dvppManager.InitDvppProcessor();
    desc.dataBuffer.data = reinterpret_cast<void *>(&dvppManager.version_);
    desc.dvppDesc.retCode = ACL_SUCCESS;
    desc.dvppDesc.channelMode = (DVPP_CHNMODE_VPC | DVPP_CHNMODE_JPEGD | DVPP_CHNMODE_JPEGE | DVPP_CHNMODE_PNGD);
    auto ret = acldvppCreateChannel(&desc);
    EXPECT_EQ(ret, ACL_SUCCESS);
    EXPECT_EQ(desc.himpiChannelIdMap.size(), 3);
}

TEST_F(HimpiTest, acldvppJpegDecodeAsync)
{
    acl::dvpp::DvppManager &dvppManager = acl::dvpp::DvppManager::GetInstance();
    dvppManager.imageProcessor_->aclRunMode_ = ACL_DEVICE;
    acldvppPicDesc picDesc = {};
    auto ret = acldvppJpegDecodeAsync(&desc, globalMem, sizeof(globalMem), &picDesc, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppJpegEncodeAsync)
{
    uint32_t size = sizeof(globalMem);
    acldvppPicDesc picDesc = {};
    acldvppJpegeConfig config = {};
    desc.dataBuffer.data = globalMem;
    desc.dataBuffer.length = sizeof(globalMem);
    acl::dvpp::DvppManager &dvppManager = acl::dvpp::DvppManager::GetInstance();
    dvppManager.imageProcessor_->aclRunMode_  = ACL_DEVICE;
    auto ret = acldvppJpegEncodeAsync(&desc, &picDesc, globalMem, &size, &config, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
    dvppManager.imageProcessor_->aclRunMode_  = ACL_HOST;
    ret = acldvppJpegEncodeAsync(&desc, &picDesc, globalMem, &size, &config, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppJpegGetImageInfo)
{
    uint32_t width = 0;
    uint32_t height = 0;
    int32_t componets = 0;
    acldvppJpegFormat format = ACL_JPEG_CSS_UNKNOWN;
    auto ret = acldvppJpegGetImageInfoV2(globalMem, sizeof(globalMem), &width, &height, &componets, &format);
    EXPECT_EQ(ret, ACL_SUCCESS);
    EXPECT_EQ(format, ACL_JPEG_CSS_GRAY);
}

TEST_F(HimpiTest, acldvppJpegPredictEncSize)
{
    acldvppPicDesc input = {};
    acldvppJpegeConfig config = {};
    uint32_t size = 0;
    auto ret = acldvppJpegPredictEncSize(&input, &config, &size);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppJpegPredictDecSize)
{
    uint32_t size = 0;
    auto ret = acldvppJpegPredictDecSize(globalMem, sizeof(globalMem), PIXEL_FORMAT_YUV_400, &size);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcResizeAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppResizeConfig config = {};
    auto ret = acldvppVpcResizeAsync(&desc, &input, &output, &config, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcCropAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppRoiConfig config = {};
    auto ret = acldvppVpcCropAsync(&desc, &input, &output, &config, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcCropResizeAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppResizeConfig resizeConfig = {};
    acldvppRoiConfig config = {};
    auto ret = acldvppVpcCropResizeAsync(&desc, &input, &output, &config, &resizeConfig, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcCropAndPasteAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppRoiConfig pasteConfig = {};
    acldvppRoiConfig config = {};
    auto ret = acldvppVpcCropAndPasteAsync(&desc, &input, &output, &config, &pasteConfig, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcCropResizePasteAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppRoiConfig pasteConfig = {};
    acldvppResizeConfig resizeConfig = {};
    acldvppRoiConfig config = {};
    auto ret = acldvppVpcCropResizePasteAsync(&desc, &input, &output, &config, &pasteConfig, &resizeConfig, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcMakeBorderAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppBorderConfig config = {};
    auto ret = acldvppVpcMakeBorderAsync(&desc, &input, &output, &config, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcBatchCropResizeMakeBorderAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppBatchPicDesc batchInput = {};
    acldvppBatchPicDesc batchOutput = {};
    batchInput.aclDvppPicDescs = &input;
    batchInput.dvppBatchPicDescs.batchSize = 1;
    batchOutput.aclDvppPicDescs = &output;
    batchOutput.dvppBatchPicDescs.batchSize = 1;
    uint32_t roiNums[1] = {1};
    acldvppBorderConfig bordConfig = {};
    acldvppRoiConfig config = {};
    std::vector<acldvppRoiConfig *> cropVec{&config};
    std::vector<acldvppBorderConfig *> borderVec{&bordConfig};
    acldvppResizeConfig resizeConfig = {};
    auto ret = acldvppVpcBatchCropResizeMakeBorderAsync(&desc, &batchInput, roiNums, 1,
        &batchOutput, cropVec.data(), borderVec.data(), &resizeConfig, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcBatchCropAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppBatchPicDesc batchInput = {};
    acldvppBatchPicDesc batchOutput = {};
    batchInput.aclDvppPicDescs = &input;
    batchInput.dvppBatchPicDescs.batchSize = 1;
    batchOutput.aclDvppPicDescs = &output;
    batchOutput.dvppBatchPicDescs.batchSize = 1;
    uint32_t roiNums[1] = {1};
    acldvppRoiConfig config = {};
    std::vector<acldvppRoiConfig *> cropVec{&config};
    acldvppBorderConfig bordConfig = {};
    std::vector<acldvppBorderConfig *> borderVec{&bordConfig};
    auto ret = acldvppVpcBatchCropAsync(&desc, &batchInput, roiNums, 1, &batchOutput, cropVec.data(), stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcBatchCropResizeAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppBatchPicDesc batchInput = {};
    acldvppBatchPicDesc batchOutput = {};
    batchInput.aclDvppPicDescs = &input;
    batchInput.dvppBatchPicDescs.batchSize = 1;
    batchOutput.aclDvppPicDescs = &output;
    batchOutput.dvppBatchPicDescs.batchSize = 1;
    uint32_t roiNums[1] = {1};
    acldvppRoiConfig config = {};
    std::vector<acldvppRoiConfig *> cropVec{&config};
    acldvppBorderConfig bordConfig = {};
    std::vector<acldvppBorderConfig *> borderVec{&bordConfig};
    acldvppResizeConfig resizeConfig = {};
    auto ret = acldvppVpcBatchCropResizeAsync(&desc, &batchInput, roiNums, 1,
        &batchOutput, cropVec.data(), &resizeConfig, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcBatchCropAndPasteAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppBatchPicDesc batchInput = {};
    acldvppBatchPicDesc batchOutput = {};
    batchInput.aclDvppPicDescs = &input;
    batchInput.dvppBatchPicDescs.batchSize = 1;
    batchOutput.aclDvppPicDescs = &output;
    batchOutput.dvppBatchPicDescs.batchSize = 1;
    uint32_t roiNums[1] = {1};
    acldvppRoiConfig config = {};
    std::vector<acldvppRoiConfig *> cropVec{&config};

    acldvppRoiConfig pasteConfig = {};
    std::vector<acldvppRoiConfig *> pasteVec{&pasteConfig};

    auto ret = acldvppVpcBatchCropAndPasteAsync(&desc, &batchInput, roiNums, 1,
        &batchOutput, cropVec.data(), pasteVec.data(), stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcBatchCropResizePasteAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppBatchPicDesc batchInput = {};
    acldvppBatchPicDesc batchOutput = {};
    batchInput.aclDvppPicDescs = &input;
    batchInput.dvppBatchPicDescs.batchSize = 1;
    batchOutput.aclDvppPicDescs = &output;
    batchOutput.dvppBatchPicDescs.batchSize = 1;
    uint32_t roiNums[1] = {1};
    acldvppRoiConfig config = {};
    std::vector<acldvppRoiConfig *> cropVec{&config};

    acldvppRoiConfig pasteConfig = {};
    std::vector<acldvppRoiConfig *> pasteVec{&pasteConfig};
    acldvppResizeConfig resizeConfig = {};
    auto ret = acldvppVpcBatchCropResizePasteAsync(&desc, &batchInput, roiNums, 1,
        &batchOutput, cropVec.data(), pasteVec.data(), &resizeConfig, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcConvertColorAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    auto ret = acldvppVpcConvertColorAsync(&desc, &input, &output, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcPyrDownAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    auto ret = acldvppVpcPyrDownAsync(&desc, &input, &output, nullptr, stream);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcEqualizeHistAsync)
{
    acldvppPicDesc input = {};
    acldvppPicDesc output = {};
    acldvppLutMap lutMap = {};
    lutMap.dvppLutMap.dims = 3;
    for (uint32_t idx = 0U; idx < lutMap.dvppLutMap.dims; ++idx) {
        lutMap.dvppLutMap.lens[idx] = LUT_MAP_DEFAULT_VALUE;
    }
    const size_t mapSize = static_cast<size_t>(lutMap.dvppLutMap.dims) *
        static_cast<size_t>(LUT_MAP_DEFAULT_VALUE);
    uint8_t *const mapAddr = new (std::nothrow)uint8_t[mapSize];
    lutMap.dvppLutMap.map = mapAddr;
    auto ret = acldvppVpcEqualizeHistAsync(&desc, &input, &output, &lutMap,stream);
    delete(mapAddr);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(HimpiTest, acldvppVpcCalcHistAsync)
{
    acldvppPicDesc input = {};
    acldvppHist hist = {};
    uint32_t histSize = 0U;
    for (uint32_t i = 0U; i < hist.dvppHistDesc.dims; ++i) {
        hist.dvppHistDesc.lens[i] = 256;
        histSize += hist.dvppHistDesc.lens[i];
    }
    uint32_t *const mapAddr = new (std::nothrow)uint32_t[histSize];
    hist.shareBuffer.data = globalMem;
    hist.shareBuffer.length = sizeof(globalMem);
    hist.dvppHistDesc.hist = mapAddr;
    auto ret = acldvppVpcCalcHistAsync(&desc, &input, &hist, nullptr, stream);
    delete(mapAddr);
    EXPECT_EQ(ret, ACL_SUCCESS);
}


TEST_F(HimpiTest, acldvppDestroyChannel)
{
    auto ret = acldvppDestroyChannel(&desc);
    EXPECT_EQ(ret, ACL_SUCCESS);
    EXPECT_EQ(desc.himpiChannelIdMap.size(), 0);
}